package com.zyy.java8.samples.stream;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * @author zhangyiying
 * @ClassName: Streams10
 * @Description: 流的收集器Collectors
 * @date 2021/12/28 14:25
 */
public class Streams10 {

    static class Person {
        String name;
        int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    public static void main(String[] args) {
        List<Person> persons =
                Arrays.asList(
                        new Person("Max", 18),
                        new Person("Peter", 23),
                        new Person("Pamela", 23),
                        new Person("David", 12));

//        test1(persons);
//        test2(persons);
//        test3(persons);
//        test4(persons);
//        test5(persons);
//        test6(persons);
//        test7(persons);
//        test8(persons);
        test9(persons);
    }

    private static void test1(List<Person> persons) {
        List<Person> filtered = persons
                .stream()
                .filter(person -> person.name.startsWith("P"))
                .collect(Collectors.toList());

        //[Peter, Pamela]
        System.out.println(filtered);
    }

    private static void test2(List<Person> persons) {
        Map<Integer, List<Person>> personByAge = persons
                .stream()
                .collect(Collectors.groupingBy(person -> person.age));

        //age 18 : [Max]
        //age 23 : [Peter, Pamela]
        //age 12 : [David]
        personByAge
                .forEach((age, person) -> System.out.printf("age %s : %s \n", age, person));

    }

    private static void test3(List<Person> persons) {
        Double averageAge = persons
                .stream()
                .collect(Collectors.averagingInt(person -> person.age));

        System.out.println(averageAge);
    }

    private static void test4(List<Person> persons) {
        IntSummaryStatistics summarizingAge = persons
                .stream()
                .collect(Collectors.summarizingInt(person -> person.age));

        //IntSummaryStatistics{count=4, sum=76, min=12, average=19.000000, max=23}
        System.out.println(summarizingAge);
    }

    private static void test5(List<Person> persons) {
        String names = persons
                .stream()
                .filter(p -> p.age >= 18)
                .map(p -> p.name)
                .collect(Collectors.joining(" and ", "In Germany ", " are of legal age."));

        //In Germany Max and Peter and Pamela are of legal age.
        System.out.println(names);
    }

    private static void test6(List<Person> persons) {
        Map<Integer, String> personMap = persons
                .stream()
                .collect(Collectors.toMap(
                        p -> p.age,
                        p -> p.name,
                        (name1, name2) -> name1 + " | " + name2
                ));
        //{18=Max, 23=Peter | Pamela, 12=David}
        System.out.println(personMap);
    }

    /**
     * 自定义Collector
     *
     * @param persons
     */
    private static void test7(List<Person> persons) {
        /**
         *  () -> new StringJoiner(" | "),          // supplier     表示返回一个以"|"为分隔符的StringJoiner对象
         *  (j, p) -> j.add(p.name.toUpperCase()),  // accumulator  表示将Person对象的name值进行大写处理后 以元素的形式加入到StringJoiner对象中
         *  (j1, j2) -> j1.merge(j2),               // combiner     merge()Java 8中StringJoiner类的方法用于合并StringJoiner str的内容，
         *                                                          该内容作为参数传递。内容被添加为下一个元素。
         *                                                          在这里并没有实际意义，仅是为了凑Collector.of的第三个参数而已，相当于(j1, j2) -> j1,
         *  StringJoiner::toString);                // finisher    表示将StringJoiner对象转换为String对象
         */
        Collector<Person, StringJoiner, String> personNameCollector =
                Collector.of(
                        () -> new StringJoiner(" | "),
                        (j, p) -> j.add(p.name.toUpperCase()),
                        (j1, j2) -> j1.merge(j2),
//                        (j1, j2) -> j1,
                        StringJoiner::toString);

        String names = persons
                .stream()
                .collect(personNameCollector);

        //MAX | PETER | PAMELA | DAVID
        System.out.println(names);
    }


    private static void test8(List<Person> persons) {

        Collector<Person, StringJoiner, String> personNameController =
                Collector.of(
                        () -> {
                            System.out.println("supplier");
                            return new StringJoiner("|");
                        },
                        (j, p) -> {
                            System.out.format("accumulator: p = %s, j = %s\n", p, j);
                            j.add(p.name.toUpperCase());
                        },
                        (j1, j2) -> {
                            System.out.println("merge");
                            return j1.merge(j2);
                        },
                        (j) -> {
                            System.out.println("finisher");
                            return j.toString();
                        });

        String personName =
                persons
                        .stream()
                        .collect(personNameController);

        /**
         * supplier
         * accumulator: p = Max, j =
         * accumulator: p = Peter, j = MAX
         * accumulator: p = Pamela, j = MAX|PETER
         * accumulator: p = David, j = MAX|PETER|PAMELA
         * finisher
         * MAX|PETER|PAMELA|DAVID
         */
        System.out.println(personName);
    }

    /**
     * 并行流处理
     * @param persons
     */
    private static void test9(List<Person> persons) {
        Collector<Person, StringJoiner, String> personNameCollector =
                Collector.of(
                        () -> {
                            System.out.println("supplier");
                            return new StringJoiner("|");
                        },
                        (j, p) -> {
                            System.out.print("accumulator: p = %s , j = %s\n");
                            j.add(p.name.toUpperCase());
                        },
                        (j1, j2) -> {
                            System.out.println("merge");
                            return j1.merge(j2);
                        },
                        (j) -> {
                            System.out.println("finisher");
                            return j.toString();
                        }
                );
        String personName =
                persons
                        .parallelStream()
                        .collect(personNameCollector);

        /**
         * supplier
         * supplier
         * supplier
         * supplier
         * accumulator: p = %s , j = %s
         * accumulator: p = %s , j = %s
         * accumulator: p = %s , j = %s
         * accumulator: p = %s , j = %s
         * merge
         * merge
         * merge
         * finisher
         * MAX|PETER|PAMELA|DAVID
         */
        System.out.println(personName);
    }


}
